package org.redmagic.agent.spring;

import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

import org.redmagic.exception.RedMagicException;
import org.redmagic.location.Location;
import org.redmagic.utils.Conditions;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

/**
 * This is the main class that will get everything started within a Spring ApplicationContext.  It will
 * search for each placeholder, and make a call to the Location to resolve the value.
 */
public class AggregatingPropertiesPlaceholderConfigurer implements BeanFactoryPostProcessor, BeanNameAware, BeanFactoryAware {

	private final AggregatingBeanDefinitionVisitor visitor;
	private final Location location;
	
	private BeanFactory beanFactory;
	
	private String beanName;
	
	public AggregatingPropertiesPlaceholderConfigurer(Location location) {
		this.location = Conditions.notNull(location, "location");
		this.visitor = new AggregatingBeanDefinitionVisitor();
	}
	
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		String[] beanNames = beanFactory.getBeanDefinitionNames();
		for (String bean : beanNames) {
			// Check that we are not parsing our own bean definition,
			// to avoid failing on unresolvable placeholders in properties file
			// locations
			if (!bean.equals(this.beanName) && beanFactory.equals(this.beanFactory)) {
				BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean);
				try {
					visitor.collectBeanDefinition(beanDefinition);
				} catch (Exception ex) {
					throw new RedMagicException(ex.getMessage(), ex);
				}
			}
		}
		
		resolveProperties(visitor);
	}

	protected void resolveProperties(AggregatingBeanDefinitionVisitor visitor) {
	    Set<String> placeholders = new HashSet<String>(visitor.getPlaceholders());
		Properties resolvedProperties = resolvePlaceholders(placeholders);
		visitor.replacePlaceholders(resolvedProperties);
	}

	protected Properties resolvePlaceholders(Set<String> placeholders) {
		return this.location.resolvePlaceholders(placeholders);
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

	@Override
	public void setBeanName(String beanName) {
		this.beanName = beanName;
	}
}